package com.king.java.tools.http.client.okhttp;

import com.king.java.tools.http.entity.ConnectEntity;
import com.king.java.tools.http.entity.HttpJsonEntity;
import com.king.java.tools.http.factory.OkhttpClientFactory;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 描述: 抽象Http请求工具
 *
 * @author : sujinchen
 * @date : 2020/10/16
 */
public abstract class AbstractOkhttp {


    private Logger log = LoggerFactory.getLogger(AbstractOkhttp.class);

    /**
     * http客户端，默认从工厂获取
     */
    protected OkHttpClient client = OkhttpClientFactory.getDefault();

    /**
     * 请求实体内容
     */
    protected final HttpJsonEntity entity;

    /**
     * 连接具体信息实体
     */
    protected final ConnectEntity connectEntity=new ConnectEntity();

    /**
     * 标记是否执行
     */
    protected boolean isRun = false;

    /**
     * 取消超时，单位ms。默认20s
     */
    private int cancelTimeOut = 20000;


    public AbstractOkhttp(OkHttpClient client, HttpJsonEntity entity) {
        this.client = client;
        this.entity = entity;
    }

    public AbstractOkhttp(HttpJsonEntity entity) {
        this.entity = entity;

    }

    /**
     * 设置请求内容
     * @param request 请求对象
     */
    public void setRequest(Request request) {
        if (request != null) {
            //设置请求行
            connectEntity.setReqLine(request.method() + " " + request.url().toString() + " " + "HTTP/1.1");
            //设置请求头
            setHeads(connectEntity.getReqHeaders(), request.headers());
            //设置请求体
            connectEntity.setReqBody(entity.getReqBody());
        } else {
            log.warn("request is null>>{}", request);
        }

    }

    /**
     * 设置响应内容
     * @param response 响应结果对象
     * @throws IOException
     */
    protected void setResponse(Response response) throws IOException {
        if (response != null) {
            //设置响应行
            connectEntity.setResLine(response.protocol().toString() + " " + response.code() + " " + response.message());
            //设置响应头
            setHeads(connectEntity.getResHeaders(), response.headers());
            //设置响应体
            connectEntity.setResBody(response.body().string());
            log.info(connectEntity.toString());
        }else {
            log.warn("response is null>>{}", response);
        }

    }

    /**
     * 头转换
     *
     * @param map
     * @param headers
     */
    protected void setHeads(Map<String, String> map, Headers headers) {
        if (headers != null && map != null) {
            for (int i = 0; i < headers.size(); i++) {
                map.put(headers.name(i), headers.value(i));
            }
        }

    }

    /**
     * 同步请求执行
     * @param request
     * @return
     */
    protected ConnectEntity synCall(Request request) {
        //设置请求内容
        setRequest(request);
        long start = System.currentTimeMillis();
        log.info("【start】:"+start);
        try (Response response = client.newCall(request).execute()) {
            long end = System.currentTimeMillis();
            log.info("【end】:"+end);
            long recation = end - start;
            log.info("【响应时长】："+(end-start));
            connectEntity.setStartTime(new Date(start));
            connectEntity.setEndTime(new Date(end));
            connectEntity.setReactionTime((int) recation);
            //记录执行情况
            isRun = true;
            if (!response.isSuccessful()) {
                connectEntity.setResLine("Unexpected code " + response);
                throw new IOException("Unexpected code " + response);
            }
            //设置响应内容
            setResponse(response);
        } catch (IOException e1) {
            // ... handle IO exception
            e1.printStackTrace();
            connectEntity.setResLine("IOException >> " + e1.getMessage());
            connectEntity.setResBody("{\"exception\":\""+e1.toString()+"\"}");
        }
        return connectEntity;
    }

    /**
     * 是否执行
     * @return
     */
    public boolean isRun() {
        return isRun;
    }


    /**
     * 设置请求客户端
     */
    public void setClient(int connectTimeOut,int writeTimeout,int readTimeout) {
       client=new OkHttpClient.Builder()
               .connectTimeout(connectTimeOut, TimeUnit.SECONDS)
               .writeTimeout(writeTimeout, TimeUnit.SECONDS)
               .readTimeout(readTimeout, TimeUnit.SECONDS)
               .build();
    }

    public void setCancel(int cancelTimeOut) {
        this.cancelTimeOut = cancelTimeOut;
    }
}
